home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************
-
- Author : Clement J Goebel III
-
- Routine converts bianary data to ASCII85 ascii
- format for transfering data via methods that are
- not bianary friendly, such as e-mail.
-
- Such that :
- (i1 * 256^3)+(i2 * 256^2)+(i3 * 256)+i4 ==
- (o1 * 85^4)+(o2 * 85^3)+(o3 * 85^2)+(o4 * 85)+o5
-
- The output must include one carrige return at least
- every 80 characters. This routine inserts a cr
- after every 8 longs of input, which represent at
- most 40 chars of output. It could be once every
- 16 longs of input representing at most 80 chars of
- output, but then the max line len could be
- interpereted as 81 characters. One other oddity
- of this implementation is that the output may
- begin with a newline char.
-
- The output buffer passed to the routine needs to
- account for the probable expansion of the data.
- Len(Output) = ((Len(Input)) * 5 + 3) / 4 + 2;
- plus room for the newline characters.
-
- *********************************************************/
-
- #define ASCII_BANG '!'
- #define ASCII_Z 'z'
- #define ASCII_TILDE '~'
- #define ASCII_GREATER_THAN '>'
- #define ASCII_CR 0x0d
- #define INPUTS_BETWEEN_CR 0x07
-
- #define k85 85L
- #define k85_2 7225L
- #define k85_3 614125L
- #define k85_4 52200625L
-
- /*------------------------------------------------------
- The processor's general purpose division is slow,
- instead I use a routine that is accurate only for
- results between 0 and 127. And to avoid speed
- loss, which would result from calling the routine
- hundreds of thousands of times, it is inserted
- inline via a macro. Note this routine is only fast
- if all of the parameters, except lDivisor,
- are registers. lRemain starts as the number to
- divide and ends up containing the remainder.
- ------------------------------------------------------*/
- #define DIV_ANS_LT_128( lRemain, lDivisor, lAns, lT ) \
- { \
- lT = (lDivisor << 6); \
- \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x40; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x20; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x10; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x08; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x04; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x02; } \
- lT = ( lT >> 1 ); \
- if ( lRemain >= lT ) { lRemain -= lT; lAns += 0x01; } \
- }
-
- /*------------------------------------------------------
- ASCII85Encode
- ------------------------------------------------------*/
- void ASCII85Encode( char *pcInput,
- unsigned long ulInputBytes,
- char *pcOutput,
- unsigned long *pulOutputBytes )
- {
- unsigned char *pcIn = (unsigned char*)pcInput;
- unsigned char *pcOut = (unsigned char*)pcOutput;
- unsigned long *plIn;
- unsigned long ulIn;
- unsigned long ulOut;
- unsigned long ulInput;
- unsigned long l;
- unsigned long ulCRs;
- unsigned char ucC;
-
- ulCRs = ulOut = 0;
- ulIn = ulInputBytes >> 2; /* longwords to read */
-
- if ( ((unsigned long) pcIn & 0x01 ) == 0 ) {
- /*------------------------------------------------------
- Input data is word aligned
- ------------------------------------------------------*/
- plIn = (unsigned long*)pcInput;
- while ( ulIn ) {
- if (((ulIn--) & INPUTS_BETWEEN_CR) == 0 ) {
- *pcOut++ = ASCII_CR;
- ulCRs++;
- }
- if ( ! ( ulInput = *plIn++ ) ) {
- *pcOut++ = ASCII_Z;
- ulOut++;
- } else {
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_4, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_3, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_2, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85 , ucC, l );
- *pcOut++ = ucC;
- *pcOut++ = ulInput + ASCII_BANG;
- }
- }
- pcIn = (unsigned char*)plIn;
- } else {
- /*------------------------------------------------------
- Else input data is NOT word aligned
- ------------------------------------------------------*/
- while ( ulIn ) {
- if (((ulIn--) & INPUTS_BETWEEN_CR) == 0 ) {
- *pcOut++ = ASCII_CR;
- ulCRs++;
- }
- ulInput = (((unsigned long)(*pcIn++)) << 24);
- ulInput = ulInput |
- ((*(unsigned long*)pcIn ) >> 8 );
- pcIn += 3;
-
- if ( ! ulInput ) {
- *pcOut++ = ASCII_Z;
- ulOut++;
- } else {
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_4, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_3, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_2, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85 , ucC, l );
- *pcOut++ = ucC;
- *pcOut++ = ulInput + ASCII_BANG;
- }
- }
- }
- /*------------------------------------------------------
- ulOut contains number of longs that were 0
- ------------------------------------------------------*/
- ulIn = ulInputBytes;
- l = (ulIn >> 2) - ulOut;/* l = # nonzero longs */
- ulOut += ( l << 2 ); /* add l * 4 */
- ulOut += ( l ); /* one more for * 5 */
-
- ulOut += ulCRs; /* # of carrige rtns */
- ulOut++; /* for last carrige rtn */
-
- /*------------------------------------------------------
- take care of leftover tail end bytes
- ------------------------------------------------------*/
- *pcOut++ = ASCII_CR;
-
- ulIn = ulIn & 0x03;
- if ( ulIn ) {
- ulInput = ((unsigned long)(*pcIn++)) << 24;
- if ( ulIn > 1 ) {
- ulInput = ulInput | ((unsigned long)
- (*pcIn++) << 16);
- if ( ulIn == 3 )
- ulInput = ulInput | ((unsigned long)
- (*pcIn++) << 8);
- }
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_4, ucC, l );
- *pcOut++ = ucC;
-
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_3, ucC, l );
- *pcOut++ = ucC;
-
- if ( ulIn > 1 ) {
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85_2, ucC, l );
- *pcOut++ = ucC;
-
- if ( ulIn == 3 ) {
- ucC = ASCII_BANG;
- DIV_ANS_LT_128( ulInput, k85, ucC, l );
- *pcOut++ = ucC;
- }
- }
- ulOut += ( ulIn + 1 );
- }
-
- /*------------------------------------------------------
- write end of data marker
- ------------------------------------------------------*/
- *pcOut++ = ASCII_TILDE;
- *pcOut++ = ASCII_GREATER_THAN;
- *pulOutputBytes = ulOut + 2;
- }
-